Micron Document
ZgRNS Git Node

Node / mirrors / LXMFy rns://a9593d0a1ff565aefd8594cbdb671af6/mirrors/LXMFy



>LXMFy

Python framework for LXMF bots on the Reticulum Network.


Features

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Category β”‚ Capabilities β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Core β”‚ Interactive CLI, command prefixes, cron-style task scheduler, middleware and eve… β”‚
β”‚ Connectivity β”‚ Direct delivery with propagation fallback, auto-peering, RNS links, opportunisti… β”‚
β”‚ Security β”‚ Spam protection, role-based permissions, identity pinning, message signature pol… β”‚
β”‚ NLP β”‚ Local offline intent classification, type-hinted argument parsing β”‚
β”‚ Extensions β”‚ Python cogs, external script cogs (Bash, Go, C, and others), subprocess sandboxi… β”‚
β”‚ Storage β”‚ JSON, SQLite, and in-memory backends, crash-safe outgoing message persistence β”‚
β”‚ Reliability β”‚ Stability and stress tests, chaos engineering hooks, resource leak checks β”‚
β”‚ UX β”‚ Help on first message, auto-generated help menus, customizable bot icons, attach… β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Installation

Requirements: Python 3.11+, RNS 1.4.2+, LXMF 1.1.1+, cbor2 5.4.0+ (pulled in with LXMFy).

From PyPI

T282828
T8b949e# pip
pip install lxmfy

T8b949e# pipx
pipx install lxmfy


From source

T282828
git clone https://github.com/Quad4-Software/LXMFy.git
Tffa657cd LXMFy
poetry install


Usage

T282828
lxmfy

Create a bot project:

T282828
lxmfy create

Debug send and receive:

T282828
lxmfy debug
lxmfy debug --config ./config --output ./lxmfy-debug-report.txt
lxmfy debug probe <destination_hash> --request-path --wait T79c0ff30
lxmfy debug send <destination_hash>
lxmfy debug receive
lxmfy debug compare <hash_a> <hash_b>


Doctor mode prints a verdict and next steps, then categorized checks (OS, shared vs owned instance, disk permissions, interfaces, announce, send pipeline / storage history, receive readiness). It saves a privacy-redacted T383838lxmfy-debug-*.txt you can share. Colors turn off when stdout is not a TTY, when T383838NO_COLOR is set, or when Windows VT is unavailable. Use T383838--no-color or T383838NO_COLOR=1 for plain output.

Docker

Build and run

From the project root:

T282828
docker build -t lxmfy-test .

T282828
docker run -d Tffea00\
--name lxmfy-test-bot Tffea00\
-v Tff7b72$(Tffa657pwdTff7b72)/config:/bot/config Tffea00\
-v Tff7b72$(Tffa657pwdTff7b72)/.reticulum:/root/.reticulum Tffea00\
--restart unless-stopped Tffea00\
lxmfy-test


Host networking (AutoInterface):

T282828
docker run -d Tffea00\
--name lxmfy-test-bot Tffea00\
--network host Tffea00\
-v Tff7b72$(Tffa657pwdTff7b72)/config:/bot/config Tffea00\
-v Tff7b72$(Tffa657pwdTff7b72)/.reticulum:/root/.reticulum Tffea00\
--restart unless-stopped Tffea00\
lxmfy-test


Build a wheel

T282828
docker build -f docker/Dockerfile.Build -t lxmfy-wheel-builder .
docker run --rm -v Ta5d6ff"Tff7b72$(Tffa657pwdTff7b72)Ta5d6ff/dist_output:/outputTa5d6ff" lxmfy-wheel-builder


That copies the built wheel into T383838./dist_output.

Example

T282828
Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3LXMFBotTb4b4b4, Te6edf3load_cogs_from_directory

Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffLXMFy Test BotTa5d6ff"Tb4b4b4, T8b949e# Name of the bot that appears on the network.
Te6edf3announceTff7b72=T79c0ff5400Tb4b4b4, T8b949e# Announce every hour, set to 0 to disable.
Te6edf3announce_enabledTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Set to False to disable all announces (both initial and periodic)
Te6edf3announce_immediatelyTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Set to False to disable initial announce
Te6edf3adminsTff7b72=Tb4b4b4[Ta5d6ff"Ta5d6ffyour_lxmf_hash_hereTa5d6ff"Tb4b4b4]Tb4b4b4, T8b949e# List of admin hashes.
Te6edf3hot_reloadingTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Enable hot reloading.
Te6edf3command_prefixTff7b72=Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4, T8b949e# Set to None to process all messages as commands.
Te6edf3cogs_dirTff7b72=Ta5d6ff"Ta5d6ffcogsTa5d6ff"Tb4b4b4, T8b949e# Specify cogs directory name.
Te6edf3rate_limitTff7b72=T79c0ff5Tb4b4b4, T8b949e# 5 messages per minute
Te6edf3cooldownTff7b72=T79c0ff5Tb4b4b4, T8b949e# 5 seconds cooldown
Te6edf3max_warningsTff7b72=T79c0ff3Tb4b4b4, T8b949e# 3 warnings before ban
Te6edf3warning_timeoutTff7b72=T79c0ff300Tb4b4b4, T8b949e# Warnings reset after 5 minutes
Te6edf3signature_verification_enabledTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Enable cryptographic signature verification
Te6edf3require_message_signaturesTff7b72=Tff7b72FalseTb4b4b4, T8b949e# Allow unsigned messages but log them
Te6edf3propagation_fallback_enabledTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Enable propagation fallback after direct delivery fails
Te6edf3propagation_nodeTff7b72=Ta5d6ff"Ta5d6ffyour_propagation_node_hash_hereTa5d6ff"Tb4b4b4, T8b949e# Manual propagation node (optional)
Te6edf3autopeer_propagationTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Auto-discover propagation nodes (optional)
Te6edf3autopeer_maxdepthTff7b72=T79c0ff4Tb4b4b4, T8b949e# Max hops for auto-peering (default: 4)
Te6edf3enable_propagation_nodeTff7b72=Tff7b72FalseTb4b4b4, T8b949e# Run as propagation node (default: False)
Te6edf3message_storage_limit_mbTff7b72=T79c0ff500Tb4b4b4, T8b949e# Storage limit in MB for propagation node (default: 500)
Te6edf3direct_delivery_retriesTff7b72=T79c0ff3Tb4b4b4, T8b949e# Number of direct delivery attempts before falling back to propagation
Te6edf3landlock_enabledTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Linux Landlock LSM sandbox for the bot process (default)
Te6edf3external_cogs_sandbox_enabledTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Sandbox external script cogs on Linux
Te6edf3external_cogs_sandbox_typeTff7b72=Ta5d6ff"Ta5d6ffautoTa5d6ff"Tb4b4b4, T8b949e# auto, landlock, bwrap, firejail, or none
Tb4b4b4)

Te6edf3load_cogs_from_directoryTb4b4b4(Te6edf3botTb4b4b4)


Tf0883e@botTff7b72.Td2a8ffcommandTb4b4b4(Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffpingTa5d6ff"Tb4b4b4, Te6edf3descriptionTff7b72=Ta5d6ff"Ta5d6ffTest if bot is responsiveTa5d6ff"Tb4b4b4)
Tff7b72def Td2a8ffpingTb4b4b4(Te6edf3ctxTb4b4b4)Tb4b4b4:
Te6edf3ctxTff7b72.Td2a8ffreplyTb4b4b4(Ta5d6ff"Ta5d6ffPong!Ta5d6ff"Tb4b4b4)


Tf0883e@botTff7b72.Td2a8ffcommandTb4b4b4(Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffechoTa5d6ff"Tb4b4b4, Te6edf3descriptionTff7b72=Ta5d6ff"Ta5d6ffEcho a messageTa5d6ff"Tb4b4b4, Te6edf3admin_onlyTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72def Td2a8ffechoTb4b4b4(Te6edf3ctxTb4b4b4, Te6edf3messageTb4b4b4: Tffa657strTb4b4b4)Tb4b4b4:
Te6edf3ctxTff7b72.Td2a8ffreplyTb4b4b4(Te6edf3messageTb4b4b4)


Te6edf3botTff7b72.Td2a8ffrunTb4b4b4(Tb4b4b4)


RRC (Reticulum Relay Chat)

Bots can join RRC hubs as ordinary clients over RNS Links with CBOR envelopes:

T282828
Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3LXMFBotTb4b4b4, Te6edf3RRCMessage

Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffRoomBotTa5d6ff"Tb4b4b4,
Te6edf3rrc_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3rrc_hubsTff7b72=Tb4b4b4[Ta5d6ff"Ta5d6ffyour_rrc_hub_destination_hashTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3rrc_roomsTff7b72=Tb4b4b4[Ta5d6ff"Ta5d6fflobbyTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3rrc_nickTff7b72=Ta5d6ff"Ta5d6ffRoomBotTa5d6ff"Tb4b4b4,
Tb4b4b4)


Tf0883e@botTff7b72.Td2a8ffon_rrc
Tff7b72def Td2a8ffon_rrcTb4b4b4(Te6edf3eventTb4b4b4, Te6edf3clientTb4b4b4, Te6edf3payloadTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3event Tff7b72== Ta5d6ff"Ta5d6ffmsgTa5d6ff" Tff7b72and Tffa657isinstanceTb4b4b4(Te6edf3payloadTb4b4b4, Te6edf3RRCMessageTb4b4b4) Tff7b72and Te6edf3payloadTff7b72.Td2a8ffmentionTb4b4b4:
Te6edf3clientTff7b72.Td2a8ffsend_messageTb4b4b4(Te6edf3payloadTff7b72.Td2a8ffroomTb4b4b4, Ta5d6fffTa5d6ff"Ta5d6ffHeard you, Tffd700{Te6edf3payloadTff7b72.Td2a8ffnickTffd700}Ta5d6ff"Tb4b4b4)


Te6edf3botTff7b72.Td2a8ffrunTb4b4b4(Tb4b4b4)


Or connect at runtime with T383838bot.connect_rrc(hub_hash, rooms=["lobby"]).

Hub sessions persist across restarts by default (T383838rrc_persist_sessions=True). Outgoing LXMF messages are also persisted by default (T383838message_persistence_enabled=True) so a crash mid-queue does not drop them. The outbound queue is bounded (T383838message_queue_size, default 50) and drops the oldest message when full.

Propagation Node Configuration

LXMFy supports three modes for propagation node usage.

Manual configuration

Set a specific propagation node by hash:

T282828
Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffMyBotTa5d6ff"Tb4b4b4,
Te6edf3propagation_fallback_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3propagation_nodeTff7b72=Ta5d6ff"Ta5d6ffyour_propagation_node_hash_hereTa5d6ff"Tb4b4b4,
Te6edf3direct_delivery_retriesTff7b72=T79c0ff3Tb4b4b4,
Tb4b4b4)


Automatic discovery (auto-peering)

Discover propagation nodes from network announces:

T282828
Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffMyBotTa5d6ff"Tb4b4b4,
Te6edf3propagation_fallback_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3autopeer_propagationTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3autopeer_maxdepthTff7b72=T79c0ff4Tb4b4b4,
Tb4b4b4)


The bot peers with suitable nodes within T383838autopeer_maxdepth hops.

Run as a propagation node

Store and forward messages for offline recipients:

T282828
Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffMyPropagationBotTa5d6ff"Tb4b4b4,
Te6edf3enable_propagation_nodeTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3message_storage_limit_mbTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)


T383838message_storage_limit_mb caps disk use. Set to 0 for unlimited storage (not recommended).

Querying propagation status

T282828
Te6edf3status Tff7b72= Te6edf3botTff7b72.Td2a8ffget_propagation_node_statusTb4b4b4(Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffCurrent outbound node: Tffd700{Te6edf3statusTb4b4b4[Ta5d6ff'Ta5d6ffcurrent_outbound_nodeTa5d6ff'Tb4b4b4]Tffd700}Ta5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffDiscovered peers: Tffd700{Te6edf3statusTb4b4b4[Ta5d6ff'Ta5d6ffdiscovered_peersTa5d6ff'Tb4b4b4]Tffd700}Ta5d6ff"Tb4b4b4)


Setting the propagation node at runtime

T282828
Te6edf3botTff7b72.Td2a8ffset_propagation_nodeTb4b4b4(Ta5d6ff"Ta5d6ffnew_propagation_node_hashTa5d6ff"Tb4b4b4)


Storage limits

T282828
Te6edf3stats Tff7b72= Te6edf3botTff7b72.Td2a8ffget_propagation_storage_statsTb4b4b4(Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffStorage used: Tffd700{Te6edf3statsTb4b4b4[Ta5d6ff'Ta5d6ffstorage_size_mbTa5d6ff'Tb4b4b4]Tffd700:Ta5d6ff.2fTffd700}Ta5d6ff MBTa5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffStorage limit: Tffd700{Te6edf3statsTb4b4b4[Ta5d6ff'Ta5d6ffstorage_limit_mbTa5d6ff'Tb4b4b4]Tffd700}Ta5d6ff MBTa5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffUtilization: Tffd700{Te6edf3statsTb4b4b4[Ta5d6ff'Ta5d6ffutilization_percentTa5d6ff'Tb4b4b4]Tffd700:Ta5d6ff.1fTffd700}Ta5d6ff%Ta5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffMessages stored: Tffd700{Te6edf3statsTb4b4b4[Ta5d6ff'Ta5d6ffmessage_countTa5d6ff'Tb4b4b4]Tffd700}Ta5d6ff"Tb4b4b4)

Te6edf3botTff7b72.Td2a8ffset_message_storage_limitTb4b4b4(Te6edf3megabytesTff7b72=T79c0ff1000Tb4b4b4)


Propagation notes

β€’ Without manual config, auto-peering, or running as a node, messages that need propagation fail
β€’ You can combine modes (manual node plus auto-peering as backup)
β€’ A propagation-node bot still sends and receives normally
β€’ Auto-peering respects T383838autopeer_maxdepth so distant nodes are skipped

Security and Sandboxing

On Linux kernels with Landlock support (5.13+), LXMFy can restrict filesystem access for the bot process and for external script cogs.

Bot process sandbox

When T383838landlock_enabled=True (default), the bot applies a Landlock LSM sandbox after startup. System paths are read-only. Bot storage, config, cogs, Reticulum config, and temp directories stay writable.

T282828
Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffSecureBotTa5d6ff"Tb4b4b4,
Te6edf3landlock_enabledTff7b72=Tff7b72TrueTb4b4b4,
Tb4b4b4)

Te6edf3status Tff7b72= Te6edf3botTff7b72.Td2a8ffget_landlock_statusTb4b4b4(Tb4b4b4)
Tffa657printTb4b4b4(Te6edf3statusTb4b4b4)


Environment overrides:

β€’ T383838LXMFY_LANDLOCK=0: disable Landlock
β€’ T383838LXMFY_LANDLOCK=1: force an attempt on Linux
β€’ unset: follow T383838landlock_enabled and kernel auto-detection

External script cog sandbox

Executable cogs in T383838cogs/ can run in a restricted environment when T383838external_cogs_sandbox_enabled=True (default). Set T383838external_cogs_sandbox_type to:

β€’ T383838auto (default): prefer Landlock, then T383838bwrap, then T383838firejail
β€’ T383838landlock: Landlock-only via T383838preexec_fn
β€’ T383838bwrap: bubblewrap read-only bind sandbox
β€’ T383838firejail: firejail private profile with no network
β€’ T383838none: no subprocess sandbox

See the docs for full configuration details.

Development

β€’ Python 3.11+
β€’ Poetry

T282828
poetry install
poetry run lxmfy run Tffa657echo


Common Makefile targets:

T282828
make lint T8b949e# ruff check
make typecheck T8b949e# pyright lxmfy
make Tffa657test T8b949e# pytest
make ci T8b949e# lint, typecheck, security check, test, build


Contributing

Send ideas and issues to LXMF: T3838387cc8d66b4f6a0e0e49d34af7f6077b5a

License
Served by rngit 1.5.2 - Generated in 0.06s